# coding:utf-8
# Author : hiicy redldw
# Date : 2019/04/17
import tensorflow as tf
import keras.applications

z = [[2, 3, 5], [1, 4, 7]]
z = tf.constant(z)
ne = tf.clip_by_value(4, -1, clip_value_max=10)
mask = z < 4
vmask = tf.cast(mask, tf.uin8)
var = (1 - vmask)  # 可以直接逆转的

tf.argmax(z, axis=1)
tf.argsort(z, axis=1, direction="DESCENDING")  # [batch,n]
tf.reduce_max(z)
tf.less(z, ne)
tf.greater(z, ne)
tf.add()
tf.add_n(z)  # 元素-wise级别相加  加列表里的元素
tf.div(z, 3)
tf.matmul(z, mask) # 矩阵乘法，可以执行批量乘法
tf.assign(z, 1)  # 全部变换 有点鸡肋...
tf.scatter_update()  # 批量更新 一个维度更新一个维度更新
tf.logical_and(True, False)  # 逻辑与、或 、非、异或
tf.boolean_mask(z, mask)  # REW:boolean_mask要降维，mask少哪一维，保留哪一维，否则降为一维
tf.clip_by_value(4, -1, clip_value_max=10)
tf.cast(mask, tf.uint8)
tf.reduce_sum(z, axis=1, keepdims=True)
tf.reshape(z, [-1, 6])  # 返回一个新节点
z.set_shape([-1, 6]) 
tf.shape(z)  # tf.shape(）返回的是一个tensor。要想知道是多少，必须通过sess.run()
tf.TensorShape([1,6,6,3])  # A list of Dimensions
z.get_shape()  # tensor.get_shape()返回的是元组(类型:Dimension)，不能放到sess.run()里面，这个里面只能放operation和tensor 
tf.nn.softmax_cross_entropy_with_logits_v2()  # label:(batch,n,21) logit:(batch,n,21)
tf.gather(z, vmask)  # 切片 按tensorflow的tensor索引来切片 只能传一维数组
tf.gather_nd(z, vmask)  # 多维多个值取，是一个值 一个值确定;numpy 是一个维度 一个维度确定
tf.losses.add_loss(ne)  # y：损失op
tf.losses.get_losses("")  # 通过损失op名字来获取
tf.convert_to_tensor([1])
tf.pad()  # paddings = [[npad, npad], [npad, npad], [1,1]] , shape=(13, 13, 5)
tf.tile(z, 1)  # 复制z一遍; multiples参数维度与input维度应一致
tf.fill([2, 3], 9)  # 传入列表，根据维度2行3列，填充某个值
tf.concat(z)  # 正常
tf.stack(z)  # 增加一个维度，值=列表里值数量
tf.tuple()  # 有点像tf.group() 返回list of tensor
tf.group()  # 用于创造一个操作，可以将传入参数的所有操作进行分组 就是组合操作 返回操作op
tf.gradients()  # 实现ys对xs求导 求得梯度
tf.stop_gradient()
tf.global_variables(self.scope + "/") # 可以获取一定范围内的变量
tf.control_dependencies()  # 接收Operation或者Tensor构成的list,在运行上下文中定义的操作（只有当内部为op操作时以来才会生效 ）之前必须执行或计算的 Operation 列表或 Tensor 对象
tf.identity(z)  # 是一个op操作表示将z的值赋予其他变量 将一个tensor转化为op 与tf.control_dependencies()经常一组配合使用
tf.nn.top_k(z, 2)  # 返回 z 中每行最大的 k 个数，并且返回它们所在位置的索引
tf.nn.in_top_k(z, [2, 3], 3)  # 返回一个布尔向量，说明目标值是否存在于预测值之中 #targets对应的索引是否在最大的前k(2)个数据中 注意 targets 是predictions中的索引位
tf.nn.embedding_lookup()  # 执行嵌入表查询
tf.SparseTensor()  # 稀疏矩阵 特定位置是value其他位置默认为0
tf.get_variable('w_1')  # 命名范围内 获取同一变量
tf.nn.moments(z)  # 计算 the mean and variance of z
tf.while_loop()  #
tf.py_func()  # 该函数被封装成graph中的一个节点（op),在执行时,func是脱离Graph的,inp的各个Tensor的值被取出来传给func作为参数,返回值会被tf.py_func转换为Tensors，
tf.map_fn(lambda x: x + 1, z)  # 对tensor里每一个值 执行传进去的函数
tf.split(z, 2,3) # 按照轴3切割2份，
tf.sets.set_intersection(a, b)  # 集合的相交、相并
tf.case()  # 控制流中的条件语句
tf.cond()  # 同上
tf.broadcast_to()#Broadcast an array for a compatible shape
tf.tensordot()  # 批量矩阵乘法
tf.string_split([z], ',')  # 传列表至少; 然后返回稀疏tensor
tf.sequence_mask()  # lengths,1维的话，那么扩展成maxlen向量，前lengths个位为true
tf.nn.rnn_cell.GRUCell()  # rnn系列模块
tf.strided_slice()  # 步长切片;就是切片语法的函数版本
tf.dynamic_partition()  # 分区操作
tf.add_to_collection()  # 加入到收集集合操作，按key来
tf.where()
tf.sparse_tensor_to_dense(z)  # 是把指定位置设为指定值，其余位置为默认值
tf.cond(tf.is_finite(v[1]), lambda: tf.stack(v), lambda: tf.zeros(3, dtype=_dtype))# 条件语句

# 集合操作
v1 = tf.get_variable(name='v1', shape=[1], initializer=tf.constant_initializer(0))
tf.add_to_collection('loss', v1)
v2 = tf.get_variable(name='v2', shape=[1], initializer=tf.constant_initializer(2))
tf.add_to_collection('loss', v2)
with tf.Session() as sess:
    sess.run(tf.initialize_all_variables())
    print(tf.get_collection('loss'))
    print(sess.run(tf.add_n(tf.get_collection('loss'))))

# partition 分区
x1 = tf.constant([[1, 1], [1, 1], [1, 2], [1, 2]], tf.float32)
x2 = tf.constant([[1, 3], [1, 2], [2, 3], [2, 4]], tf.float32)
# ones = tf.ones([2,1], dtype=tf.float32)
partitions = [1, 0, 1, 0]
result = tf.dynamic_partition(x1, partitions, 2)

# 读文件
image_value = tf.read_file('D:/picture/11.jpg')
img = tf.image.decode_jpeg(image_value, channels=3)

# where 条件
x = [[1, 2, 3], [4, 5, 6]]
y = [[7, 8, 9], [10, 11, 12]]
condition3 = [[True, False, False],
              [False, True, True]]
condition4 = [[True, False, False],
              [True, True, False]]
with tf.Session() as sess:  # 全部相同维度; tf.where 只有条件时 返回点坐标 ; 不需要维度相同
    print(sess.run(tf.where(condition3, x, y)))
    print(sess.run(tf.where(condition4, x, y)))

#########################################
# map_fn
# map_fn(fn, elems, dtype=None, parallel_iterations=None, back_prop=True,
#            swap_memory=False, infer_shape=True, name=None)

###########################################
t = tf.constant([[[1, 1, 1], [2, 2, 2]],
                 [[3, 3, 3], [4, 4, 4]],
                 [[5, 5, 5], [6, 6, 6]]])
tf.strided_slice(t, [1, 0, 0], [2, 1, 3], [1, 1, 1])  # 等价于numpy的t[1:2:1,0:1:1,0:3:1]

###########################################
tf.custom_gradient
# 自己重写节点梯度
@tf.custom_gradient
def DoublySign(x):
    def grad(dy):
        '''
        dy 是从反向而言的上一层的梯度
        '''
        cond = (x >= -1) & (x <= 1)
        zeros = tf.zeros_like(dy)
        return tf.where(cond,dy,zeros) 
    # 这里相当于是在自己手动计算梯度，如果在-1和1之间，将sign的函数梯度修改为1，根据链式法则，梯度为dy*1=dy
    # 而其他情况下，梯度为dy*0=0
    # tf.where 和 tf.cond 的区别 https://blog.csdn.net/xiadimichen14908/article/details/83592282
    return tf.sign(x),grad

##########################################################
# 赋值
# stack concat
# 索引
# gather
